/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.gobygang.server;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import com.gobygang.shared.ChitInfo;
import com.gobygang.shared.TaxiGangInfo;
import com.google.appengine.api.datastore.Key;


@Entity
@Table(name = "TAXIGANG")
@NamedQueries({	@NamedQuery(	name = "TaxiGang.findAll", 				query = "SELECT a FROM TaxiGang a "), 
	@NamedQuery(	name = "TaxiGang.findByKey", 			query = "SELECT a FROM TaxiGang a WHERE a.taxigangid = :taxigangid"), 
	@NamedQuery(	name = "TaxiGang.findByTaxiGangid", 	query = "SELECT a FROM TaxiGang a WHERE a.taxigangid = :taxigangid"), 
	@NamedQuery(	name = "TaxiGang.findByStatus", 		query = "SELECT a FROM TaxiGang a WHERE a.status = :status"), 
	@NamedQuery(	name = "TaxiGang.findByProximity", 		query = "SELECT a FROM TaxiGang a WHERE a.status = 'OPEN' AND (a.geobox = :geobox00 or a.geobox =:geobox01 or a.geobox =:geobox02 OR a.geobox = :geobox10 or a.geobox = :geobox11 or a.geobox = :geobox12 OR a.geobox = :geobox20 or a.geobox = :geobox21 or a.geobox = :geobox22)"), 
	@NamedQuery(    name = "TaxiGang.findByLeader", 	    query = "SELECT a FROM TaxiGang a WHERE a.leader = :leader"),
	@NamedQuery(    name = "TaxiGang.findByMember1", 	    query = "SELECT a FROM TaxiGang a WHERE a.member1 = :member1"),
	@NamedQuery(    name = "TaxiGang.findByMember2", 	    query = "SELECT a FROM TaxiGang a WHERE a.member2 = :member2"),
	@NamedQuery(    name = "TaxiGang.findByMember3", 	    query = "SELECT a FROM TaxiGang a WHERE a.member3 = :member3"),
	@NamedQuery(    name = "TaxiGang.findMyTaxigangs", 	    query = "SELECT a FROM TaxiGang a WHERE a.my.id = :id")
})
public class TaxiGang implements Serializable {
	public enum Status {
		OPEN {
			public String toString() {
				return "OPEN";
			}
		},
		FULL {
			public String toString() {
				return "FULL";
			}
		},
		PROCEEDING {
			public String toString() {
				return "PROCEEDING";
			}
		},
		CLOSED {
			public String toString() {
				return "CLOSED";
			}
		},
		DONT_SHOW {
			public String toString() {
				return "DONT_SHOW";
			}
		}
	}
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "TAXIGANGID", nullable = false)
	private Key key;
	@Column(name = "DESCRIPTION", nullable = true)
	private String description;

	@Column(name = DEPARTURETIME, nullable = false)
	private Date departureTime;
	@Column(name = TIMEZONEOFFSET, nullable = true)
	private Integer timeZoneOffset;
	@Column(name = CREATIONTIME, nullable = false)
	private Date creationTime;
	@Column(name = STARTCITY, nullable = true)
	private String startCity;
	@Column(name = DESTINATIONCITY, nullable = true)
	private String destinationCity;
	@Column(name = STARTADDRESS, nullable = true)
	private String startAddress;
	@Column(name = DESTINATIONADDRESS, nullable = true)
	private String destinationAddress;
	@Column(name = GEOBOX, nullable = true)
	private long geobox;
	@Column(name = STARTLAT, nullable = true)
	private double startLat;
	@Column(name = STARTLNG, nullable = true)
	private double startLng;
	@Column(name = DESTINATIONLAT, nullable = true)
	private double destinationLat;
	@Column(name = DESTINATIONLNG, nullable = true)
	private double destinationLng;
	@Column(name = TAXIGANGSTATUS, nullable = false)
	private String status;
	@Column(name = PERMANENT, nullable = true)
	private Boolean permanent;
	@Column(name = GANGLEADER, nullable = true)
	private Long leaderId;
	@Column(name = MEMBERS, nullable = true)
	@OneToMany(mappedBy = "taxiGang", cascade = CascadeType.ALL)
	private ArrayList<Long> members = new ArrayList<Long>();

	@Column(name = AWARDING_MEMBERS, nullable = true)
	@OneToMany(cascade = CascadeType.ALL)
	private ArrayList<Long> awardingMembers = new ArrayList<Long>();

//    @ManyToOne(fetch = FetchType.LAZY)
//    private Long my;

//	@Column(name = MEMBER1, nullable = true)
//	private String member1;
//	@Column(name = MEMBER1NAME, nullable = true)
//	private String member1Name;
//	@Column(name = MEMBER2, nullable = true)
//	private String member2;
//	@Column(name = MEMBER2NAME, nullable = true)
//	private String member2Name;
//	@Column(name = MEMBER3, nullable = true)
//	private String member3;
//	@Column(name = MEMBER3NAME, nullable = true)
//	private String member3Name;
	@Column(name = LOCALE, nullable = true)
	private String locale;
	@Column(name = PAGE, nullable = true)
	private String page;
	@Column(name = PAGEACCESSTOKEN, nullable = true)
	private String pageAccessToken;
	@Column(name = MESSAGES, nullable = true)
	@OneToMany(mappedBy = "taxiGang", cascade = CascadeType.ALL)
	private ArrayList<Chit> messages = new ArrayList<Chit>();

	@Column(name = POSTALCODE, nullable = true)
	private String postalCode;

	public static final  String DEPARTURETIME="DEPARTURETIME";
	public static final  String TIMEZONEOFFSET="TIMEZONEOFFSET";

	public static final  String CREATIONTIME="CREATIONTIME";
	public static final  String STARTCITY="STARTCITY";
	public static final  String DESTINATIONCITY="DESTINATIONCITY";
	public static final  String STARTADDRESS="STARTADDRESS";
	public static final  String DESTINATIONADDRESS="DESTINATIONADDRESS";
	public static final  String GEOBOX="GEOBOX";
	public static final  String STARTLAT="STARTLAT";
	public static final  String STARTLNG="STARTLNG";
	public static final  String DESTINATIONLAT="DESTINATIONLAT";
	public static final  String DESTINATIONLNG="DESTINATIONLNG";
	public static final  String TAXIGANGSTATUS="TAXIGANGSTATUS";
	public static final  String PERMANENT="PERMANENT";
	public static final  String TAXIGANGID="TAXIGANGID";
	public static final  String GANGLEADER="GANGLEADER";
	public static final  String GANGLEADERNAME="GANGLEADERNAME";
	public static final  String MEMBER1="MEMBER1";
	public static final  String MEMBER1NAME="MEMBER1NAME";
	public static final  String MEMBER2="MEMBER2";
	public static final  String MEMBER2NAME="MEMBER2NAME";
	public static final  String MEMBER3="MEMBER3";
	public static final  String MEMBER3NAME="MEMBER3NAME";
	public static final  String MESSAGES="MESSAGES";
	public static final  String MEMBERS="MEMBERS";
	public static final  String AWARDING_MEMBERS="AWARDING_MEMBERS";
	public static final  String POSTALCODE="POSTALCODE";
	public static final  String LOCALE="LOCALE";
	public static final  String PAGE="PAGE";
	public static final  String PAGEACCESSTOKEN="PAGEACCESSTOKEN";
	
	private static SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm ");

	public TaxiGang(TaxiGangInfo info, ChitInfo chitInfo, String[] pageDetails) {
		creationTime = new Date();
		setInfo(info);
		setStatus(Status.OPEN);
		addMessage(chitInfo);
		setPage(pageDetails[0]);
		setPageAccessToken(pageDetails[1]);
		permanent = false;
	}

	public void addLeader(TaxiGanguser leader){
		this.leaderId = leader.getId();
		addMember(leader.getId());
	}
	
	private void setPage(String page){
		this.page=page;
	}
	private void setPageAccessToken(String pageAccessToken){
		this.pageAccessToken=pageAccessToken;
	}
	public void addMessage(ChitInfo chitInfo){
		if (chitInfo != null){
			Chit chit = new Chit(chitInfo.getAuthorName(), chitInfo.getChitText(),chitInfo.getMobileNumber());
			messages.add(chit);
		}
	}
	
	
	public void setInfo(TaxiGangInfo info) {
		this.startAddress = info.getStart();
		this.destinationAddress = info.getDestination();

		this.startLat = info.getStartLat();
		this.startLng = info.getStartLng();
		this.destinationLat = info.getDestinationLat();
		this.destinationLng = info.getDestinationLng();
		this.postalCode = info.getPostalCode();
		this.locale = info.getLocale();

		geobox = GeoBox.getInstance().getIndex(this.startLat, this.startLng);

		//    	leaderName = info.getLeaderName();
		//    	info.setMember1Name(member1Name);
		//    	info.setMember2Name(member2Name);
		//    	info.setMember3Name(member3Name);

		timeZoneOffset = info.getTimeZoneOffset();

		int departureMinutes = info.getDepartureHour()*60 + info.getDepartureMinute() + info.getTimeZoneOffset();
		int departureHour = departureMinutes/60;
		if (departureHour < 0){
			departureHour +=24;
		}
		int departureMinute = departureMinutes%60;

		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.DAY_OF_MONTH, info.getDepartureDay());
		calendar.set(Calendar.MONTH, info.getDepartureMonth());
		calendar.set(Calendar.YEAR, info.getDepartureYear()+1900);

		calendar.set(Calendar.HOUR_OF_DAY, departureHour);
		calendar.set(Calendar.MINUTE, departureMinute);
		departureTime = calendar.getTime();
		if (departureTime.before(creationTime)){
			//tomorrow
			calendar.add(Calendar.DAY_OF_YEAR, 1);
			departureTime = calendar.getTime();
		}

	}

	public TaxiGangInfo getInfo() {
		TaxiGangInfo info = new TaxiGangInfo();
		info.setStatus(status);
		info.setId(key.getId());
		info.setStart(startAddress);
		info.setStartLat(startLat);
		info.setStartLng(startLng);
		info.setDestinationLat(destinationLat);
		info.setDestinationLng(destinationLng);
		info.setDestination(destinationAddress);
		info.setCreationTime(creationTime);
		info.setPostalCode(postalCode);

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(departureTime);
		calendar.add(Calendar.HOUR_OF_DAY, -timeZoneOffset/60);
		//       	int gmtDepartureHours = calendar.get(Calendar.HOUR_OF_DAY);
		//       	int gmtMinutes = calendar.get(Calendar.MINUTE) + gmtDepartureHours*60;
		//       	int localMinutes = gmtMinutes - timeZoneOffset;
		//       	int localHours = localMinutes/60;
		//       	if (localHours >= 24){
		//       		localHours -= 24;
		//       	}
		//       	localMinutes = (gmtMinutes%60)/15*15;
		//       	
		//       	info.setDepartureHour(localHours);
		//       	info.setDepartureMinute(localMinutes);
		//       	
		//       	calendar.set(Calendar.HOUR_OF_DAY, localHours);
		//       	calendar.set(Calendar.MINUTE, localMinutes);
		info.setLocalDepartureTime(calendar.getTime());
		
		String formattedDepartureTime = sdf.format(calendar.getTime());
		info.setDepartureTime(formattedDepartureTime);
		
		
		Long[] memberInfoList = new Long[members.size()];
		int i=0;
		//first leader
		for (Long memberId : members){
			if (memberId==leaderId){
				memberInfoList[i++]=memberId;
				//info.setLeaderName(member.getDisplayname());

			}
		}
		//then members
		for (Long memberId : members){
			if (memberId!=leaderId){
				memberInfoList[i++]=memberId;
			}
		}
		info.setMemberIds(memberInfoList);
//		info.setMemberName(1,mangle(member1Name));
//		info.setMemberName(2,mangle(member2Name));
//		info.setMemberName(3,mangle(member3Name));
//
//		int numMembers =0;
//		if (member1 != null){
//			numMembers++;
//		}
//		if (member2 != null){
//			numMembers++;
//		}
//		if (member3 != null){
//			numMembers++;
//		}
//		info.setNumMembers(numMembers);
		
		//messages
		List<ChitInfo>listChitInfo = new ArrayList<ChitInfo>();
		for (Chit chit: messages){
			ChitInfo chitInfo = chit.getInfo();
			listChitInfo.add(chitInfo);
		}
		info.setChitInfo(listChitInfo.toArray(new ChitInfo[0]));
		
		//info.setLink("http://apps.facebook.com/taxigang/?tg="+info.getId()+"&locale="+locale);
		info.setLink("http://www.taxigang.com/?tg="+info.getId()+"&locale="+locale);

		info.setPage(page);
		info.setPageAccessToken(pageAccessToken);
		return info;
	}


	public long getKeyId() {
		return key.getId();
	}


	public long getGeobox() {
		return geobox;
	}

	public double getStartLat() {
		return startLat;
	}

	public double getStartLng() {
		return startLng;
	}




	
	public List<Long> getMembers(){
		return members;
	}

	public void addMember(Long taxiGangUserId) {
		members.add(taxiGangUserId);			
	}
	
	public void removeMember(TaxiGanguser taxiGangUser) {
		members.remove(taxiGangUser.getId());
	}

	public Status getStatus() {
		if (status.equals("CLOSED")) return Status.CLOSED;
		if (status.equals("OPEN")) return Status.OPEN;
		return null;
	}

	public void setStatus(Status status) {
		this.status = status.toString();
	}

	public String getStartAddress() {
		return startAddress;
	}
	public String getDestinationAddress() {
		return destinationAddress;
	}

	public String getDescription() {
		return description;
	}

	public Date getDepartureTime() {
		return departureTime;
	}
	
	public Boolean getPermanent() {
		return permanent;
	}
	public void setDepartureTime(Date departureTime) {
		this.departureTime=departureTime;
	}
	
	@Override
	public int hashCode() {
		int hash = 0;
		hash += (key != null ? key.hashCode() : 0);
		return hash;
	}

	@Override
	public boolean equals(Object object) {
		// TODO: Warning - this method won't work in the case the id fields are not set
		if (!(object instanceof TaxiGang)) {
			return false;
		}
		TaxiGang other = (TaxiGang) object;
		if ((this.key == null && other.key != null) || (this.key != null && !this.key.equals(other.key))) {
			return false;
		}
		return true;
	}

	@Override
	public String toString() {
		return "taxigangsystem.beans.TaxiGang[taxigangid=" + key.getId() + "]";
	}

	public void prepareRemoval() {
//		for (Long userId : members){
//			user.removeTaxigang(this);
//		}
	}

	public void addAwardingUser(Long userId) {
		awardingMembers.add(userId);		
	}

	public List<Long> getAwardingUsers() {
		return awardingMembers;		
	}

}
